/*************************************************************************
                           Feu  -  description
                             -------------------
    début                : Feu
    copyright            : (C) Feu par XXX
    e-mail               : Feu
*************************************************************************/

//---------- Réalisation de la tâche <Feu> (fichier Feu.cpp) ---

/////////////////////////////////////////////////////////////////  INCLUDE
//-------------------------------------------------------- Include système
#include <signal.h>
#include <iostream>
#include <sys/sem.h>
#include <cstdlib>

//------------------------------------------------------ Include personnel
#include "Feu.h"
#include "/public/tp/tp-multitache/Outils.h"
using namespace std;
///////////////////////////////////////////////////////////////////  PRIVE
//------------------------------------------------------------- Constantes
//etat des feux E-O
static const int VERT = 0x00;
static const int ROUGE = 0x01;
//etat des feux N-S
static const int VERT2 = 0x00 << 1;
static const int ROUGE2 = 0x01 << 1;

//------------------------------------------------------------------ Types

//---------------------------------------------------- Variables statiques
static unsigned int tempo; 
//Au départ les feux E-O sont verts et les feux N-S sont rouges : 
static int etat = (VERT | ROUGE2);
static int* shmTempo;
static int* shmEtat;

static struct sigaction fin; //declaration du handler

//Ini des sémaphores :	
static int sem;
static struct sembuf reserverTempo ={0,-1,0};//Permet de reserver le premier sémaphore de maniere bloquante
static struct sembuf libererTempo ={0,1,0};//liberer le premier sémaphore
static struct sembuf reserverEtat ={1,-1,0};//Reserver le deuxieme sémaphore de maniere bloquante
static struct sembuf libererEtat ={1,1,0};//Liberer le deuxieme sémaphore

//------------------------------------------------------ Fonctions privées
//static type nom ( liste de paramètres )
// Mode d'emploi :
//
// Contrat :
//
// Algorithme :
//
//{
//} //----- fin de nom
static void moteurFeu()
{
	enum TypeZone axeVert;
	enum TypeZone axeRouge;
	enum TypeZone zoneDureeVert;
	enum TypeZone zoneDureeRouge;
	for (;;)
	{
		int feuRouge;
		semop(sem, &reserverTempo, 1); 
		tempo = *shmTempo; //Recuperer la valeur de la tempo
		semop(sem, &libererTempo, 1);

		unsigned int tempoNS = tempo >> 16;
		unsigned int tempoEO = tempo & 0xFFFF;
		Effacer (DUREE_AXE_NS);
		Effacer (DUREE_AXE_EO);
		Afficher ( DUREE_AXE_NS, tempoNS, GRAS);
		Afficher ( DUREE_AXE_EO, tempoEO, GRAS);


		if ((etat) == 0x02)
		{
			//Le feu n°1 est vert :
			tempo = tempoEO;
			cerr << "la tempo sur la voie E-O est : " << tempo << endl;
			feuRouge = 1;
			axeVert = COULEUR_AXE_EO;
			axeRouge = COULEUR_AXE_NS;
			zoneDureeVert = TEMPS_AXE_EO;
			zoneDureeRouge = TEMPS_AXE_NS;
		}
		else
		{
			//Le feu n°2 est vert :
			tempo = tempoNS;
			cerr << "la tempo sur la voie N-S est : " << tempo << endl;
			feuRouge = 0;
			axeVert = COULEUR_AXE_NS;
			axeRouge = COULEUR_AXE_EO;
			zoneDureeVert = TEMPS_AXE_NS;
			zoneDureeRouge = TEMPS_AXE_EO;
		}
		Effacer (axeVert);
		Effacer (axeRouge);
		Afficher ( axeVert, "Vert", GRAS);
		Afficher ( axeRouge, "Rouge", GRAS, INVERSE);

		//Atendre jusqu'a l'expiration de la tempo : 
		for (unsigned int i = tempo; i>0; i--)
		{
			Effacer (zoneDureeVert);
			Effacer (zoneDureeRouge);
			Afficher (zoneDureeVert, i);
			Afficher (zoneDureeRouge, i+5);
			sleep (1);
		}

		//Les feux verts passent à l'orange pour 3 secondes :
		etat = ROUGE | ROUGE2;
		semop(sem, &reserverEtat, 1);
		(*shmEtat) = etat; //Ecrire le nouvel état des feux
		semop(sem, &libererEtat, 1);
		cerr << "feu a changé d'état : "<<etat<<"dans : "<<*shmEtat<<endl;		
		Effacer (axeVert);
		Afficher ( axeVert, "Orange", GRAS, INVERSE);

		for (unsigned int i = 3; i>0; i--)
		{
			Effacer (zoneDureeVert);
			Effacer (zoneDureeRouge);
			Afficher (zoneDureeVert, i);
			Afficher (zoneDureeRouge, i+2);
			sleep (1);
		}

		//Les feux passent au rouge pour 2 secondes : 

		Effacer (axeVert);
		Afficher ( axeVert, "Rouge", GRAS, INVERSE);

		for (unsigned int i = 2; i>0; i--)
		{
			Effacer (zoneDureeVert);
			Effacer (zoneDureeRouge);
			Afficher (zoneDureeVert, i);
			Afficher (zoneDureeRouge, i);
			sleep (1);
		}
		
		//Le feu qui etait rouge repasse au vert :
		etat ^= (0x01 << feuRouge);
		semop(sem, &reserverEtat, 1);
		(*shmEtat) = etat; //Ecrire le nouvel état des feux
		semop(sem, &libererEtat, 1);	
		cerr << "feu a changé d'état : "<<etat<<"dans : "<<*shmEtat<<endl;		
	}
}

static void finDeTache(int signum)
{
//On s'assure de rendre les ressources avant de mourir pour ne pas bloquer Menu ou GestionPriorites
	semctl ( sem,0,SETVAL,1 );
	semctl ( sem,1,SETVAL,1 );
	cerr << "fin de feu..." << endl;
	exit ( 0 );
} 
static int creerHandler()
{
	cerr << "tentative de création du handler de SIGUSR2 pour feu" << endl;
	sigfillset(&fin.sa_mask); //a la reception du signal on masque tout les autres signaux
	fin.sa_handler = finDeTache; //fonction appelée par le handler
	fin.sa_flags = 0; //pas de flags utiles
	return sigaction(SIGUSR2,&fin,0); //associer la reception de SIGUSR2 au handler "fin", pas de sauvegarde de l'ancien handler : il n'y en a pas..
}

//////////////////////////////////////////////////////////////////  PUBLIC
//---------------------------------------------------- Fonctions publiques
// Algorithme :
//
 //----- fin de Nom
void Feu(void* ATempoFeu, void* AEtatFeu, int Sem)
{
	while (creerHandler() == -1)
	{
		cerr << "echec de la création du handler" << endl;
	}
	
	sem = Sem;
//Ini des shm
	shmTempo = (int*)ATempoFeu;
	shmEtat = (int*)AEtatFeu;

//Demarage de la phase moteur :
	moteurFeu();
}
